package heiing.collection.tree;

import heiing.collection.map.MapDiff;
import heiing.collection.map.MapDiffResult;
import java.util.Map;

/**
 * 找到两树的差异
 * @author heiing
 */
public class TreeDiff {

    private TreeDiff() {}

    /**
     * 根据树节点的ID比较两棵树的差异
     * @param <K> 树节点的ID的类型
     * @param <T> 树节点的类型
     * @param a 第一棵树
     * @param b 第二棵树
     * @return 返回两棵树的差异。节点ID在 b 中而不在 a 中的为新增节点，在 a 中而不在 b 中的为已删除的节点，同时在 a 与 b 中且节点发生变更的为修改过的节点
     */
    public static <K, T> MapDiffResult<K, T> diff(Tree<T, K> a, Tree<T, K> b) {
        return MapDiff.diff(null == a ? null : a.getNodesMap(), null == b ? null : b.getNodesMap());
    }

    /**
     * 根据树节点的全限定名称比较两棵树的差异
     * @param <K> 树节点的ID的类型
     * @param <T> 树节点的类型
     * @param a 第一棵树
     * @param b 第二棵树
     * @param pathSeparator 全限定名称中，用于连接父子之间的名称的分隔符，参见 <code>Tree::getNamePath</code>
     * @return 返回两棵树的差异。全限定名称在 b 中而不在 a 中的为新增节点，在 a 中而不在 b 中的为已删除的节点，同时在 a 与 b 中且节点发生变更的为修改过的节点
     */
    public static <K, T> MapDiffResult<String, T> diffByNamePath(Tree<T, K> a, Tree<T, K> b, String pathSeparator) {
        Map<String, T> am = null == a ? null : a.toMap((k, t) -> t.getNamePath(k, pathSeparator));
        Map<String, T> bm = null == b ? null : b.toMap((k, t) -> t.getNamePath(k, pathSeparator));
        return MapDiff.diff(am, bm);
    }

}
